package com.mi.soul.whale.module.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mi.rule.cache.CacheKit;
import com.mi.rule.db.core.MiPage;
import com.mi.rule.db.core.MiWrapper;
import com.mi.rule.db.dao.MiDao;
import com.mi.rule.resource.ResEntity;
import com.mi.rule.resource.ResourceHandler;
import com.mi.rule.util.TreeKit;
import com.mi.rule.util.project.SRS;
import com.mi.soul.whale.common.util.BaseService;
import com.mi.soul.whale.module.system.service.SystemService;
import com.mi.soul.whale.mybatis.entity.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源表 服务实现类
 * </p>
 *
 * @author 王永吉
 */
@Slf4j
@Service
public class SystemServiceImpl extends BaseService implements SystemService {
    @Autowired
    private MiDao miDao;

    //资源列表
    public List<SysResource> resources() {
        Object o = CacheKit.get("cache-system-resource-list");
        if (o == null) {
            List<SysResource> list = miDao.list(SysResource.class);
            CacheKit.set("cache-system-resource-list", list);
            return list;
        }
        return (List<SysResource>) o;
    }

    //角色列表
    public List<SysRole> roles() {
        Object o = CacheKit.get("cache-system-role-list");
        if (o == null) {
            List<SysRole> list = miDao.list(SysRole.class);
            CacheKit.set("cache-system-role-list", list);
            return list;
        }
        return (List<SysRole>) o;
    }

    //菜单列表
    public List<SysMenu> menus() {
        Object o = CacheKit.get("cache-system-menu-list");
        if (o == null) {
            List<SysMenu> list = miDao.list(SysMenu.class);
            CacheKit.set("cache-system-menu-list", list);
            return miDao.list(SysMenu.class);
        }
        return (List<SysMenu>) o;
    }

    //角色菜单Urls
    public List<String> roleMenuUrls(Object roleId) {
        Object o = CacheKit.get("cache-system-role-menu-url-" + roleId);
        if (o == null) {
            List<Object> menuIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.MENU_ID).eq(SysLinkRoleMenu.ROLE_ID, roleId));
            List<SysMenu> sysMenus = miDao.listByIds(SysMenu.class, menuIds);
            List<String> urls = sysMenus.stream().map(SysMenu::getPath).collect(Collectors.toList());
            CacheKit.set("cache-system-role-menu-url-" + roleId, urls);
            return urls;
        }
        return (List<String>) o;
    }

    //角色菜单List
    public List<SysMenu> roleMenuList(Object roleId) {
        Object o = CacheKit.get("cache-system-role-menu-list-" + roleId);
        if (o == null) {
            List<Object> menuIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.MENU_ID).eq(SysLinkRoleMenu.ROLE_ID, roleId));
            List<SysMenu> sysMenus = miDao.listByIds(SysMenu.class, menuIds);
            CacheKit.set("cache-system-role-menu-list-" + roleId, sysMenus);
            return sysMenus;
        }
        return (List<SysMenu>) o;
    }

    //角色资源Urls
    public List<String> roleResourceUrls(Object roleId) {
        Object o = CacheKit.get("cache-system-role-resource-url-" + roleId);
        if (o == null) {
            List<Object> resourceIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select(SysLinkRoleResource.RESOURCE_ID).eq(SysLinkRoleResource.ROLE_ID, roleId));
            List<SysResource> sysMenus = miDao.listByIds(SysResource.class, resourceIds);
            List<String> urls = sysMenus.stream().map(SysResource::getUrl).collect(Collectors.toList());
            CacheKit.set("cache-system-role-resource-url-" + roleId, urls);
            return urls;
        }
        return (List<String>) o;
    }

    //角色资源List
    public List<SysResource> roleResourceList(Object roleId) {
        Object o = CacheKit.get("cache-system-role-resource-list-" + roleId);
        if (o == null) {
            List<Object> resourceIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select(SysLinkRoleResource.RESOURCE_ID).eq(SysLinkRoleResource.ROLE_ID, roleId));
            List<SysResource> sysMenus = miDao.listByIds(SysResource.class, resourceIds);
            CacheKit.set("cache-system-role-resource-list-" + roleId, sysMenus);
            return sysMenus;
        }
        return (List<SysResource>) o;
    }

    //1.清除已失效资源
    //2.添加新资源
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS systemResourceCleanAdd(SRS param) {
        //项目中的全部资源
        ArrayList<ResEntity> resMList = ResourceHandler.getResMList();
        ArrayList<ResEntity> resCList = ResourceHandler.getResCList();
        ArrayList<ResEntity> resList = new ArrayList<>();
        resList.addAll(resCList);
        resList.addAll(resMList);
        List<String> resUrlList = resList.stream().map(ResEntity::getUrl).collect(Collectors.toList());

        //数据库中的全部资源
        List<SysResource> dbResList = miDao.list(SysResource.class);
        List<String> dbUrlList = dbResList.stream().map(SysResource::getUrl).collect(Collectors.toList());

        //筛选Method
        //待删除模块 -- deleteResCIds
        //新增模块   -- insertResC
        //可更新模块 -- updateResC
        ArrayList<SysResource> insertResCList = new ArrayList<>();
        ArrayList<String> deleteResCIds = new ArrayList<>();
        ArrayList<SysResource> updateResCList = new ArrayList<>();

        //筛选controller
        for (ResEntity resEntity : resList) {
            String resUrl = resEntity.getUrl();
            //待新增  -- 项目中存在，数据库中不存在
            if (!dbUrlList.contains(resUrl)) {
                SysResource sysResource = new SysResource();
                sysResource.setName(resEntity.getName());
                sysResource.setParentName(resEntity.getParentName());
                sysResource.setUrl(resEntity.getUrl());
                sysResource.setPid("0");//初始为0后面会做修改
                insertResCList.add(sysResource);
            }
        }
        for (SysResource sysResource : dbResList) {
            String dbUrl = sysResource.getUrl();
            //待更新 -- 数据库中存在，项目中存在
            if (resUrlList.contains(dbUrl)) {
                List<ResEntity> collect = resList.stream().filter(it -> it.getUrl().equals(dbUrl)).collect(Collectors.toList());
                ResEntity resEntity = collect.get(0);
                sysResource.setName(resEntity.getName());
                sysResource.setParentName(resEntity.getParentName());
                updateResCList.add(sysResource);
            }

            //待删除 -- 数据库中存在，项目中不存在
            if (!resUrlList.contains(dbUrl)) {
                deleteResCIds.add(sysResource.getId());
            }
        }

        //删除失效资源
        if (deleteResCIds.size() > 0) {
            //删除资源表
            long l = miDao.deleteByIds(SysResource.class, deleteResCIds);
            //删除角色资源关联表
            MiWrapper<SysLinkRoleResource> wrapper = new MiWrapper<>(SysLinkRoleResource.class);
            wrapper.in(SysLinkRoleResource.ROLE_ID, deleteResCIds);
            long delete = miDao.delete(wrapper);
            log.info("失效资源ids:{}", deleteResCIds);
            log.info("删除失效资源      共{}条", l);
            log.info("删除角色资源关联表 共{}条", delete);
        }

        //更新资源
        if (updateResCList.size() > 0) {
            //更新资源
            long l = miDao.updateBatchById(updateResCList);
            log.info("更新资源      共{}条", l);
        }

        //添加新资源
        //
        //批量插入资源
        long l = miDao.insertBatch(insertResCList);
        log.info("批量插入资源     共{}条", l);
        log.info("批量插入资源      {}", JSON.toJSONString(insertResCList));

        //把新增 和 修改的资源 合并
        ArrayList<SysResource> allResC = new ArrayList<>();
        allResC.addAll(insertResCList);
        allResC.addAll(updateResCList);

        //遍历 新增模块
        for (SysResource insertRes : insertResCList) {
            //处理非根节点
            if (!insertRes.getName().equals(insertRes.getParentName())) {
                String parentName = insertRes.getParentName();
                //从合并的模块集合内
                for (SysResource sysResource : allResC) {
                    //找到自己的pid
                    if (sysResource.getName().equals(parentName)) {
                        insertRes.setPid(sysResource.getId());
                        break;
                    }
                }
            }
        }

        //更新这个集合，模块新增完成
        long l1 = miDao.updateBatchById(insertResCList);
        log.info("全部资源新增完成      共{}条", l1);
        log.info("全部资源新增完成      {}", JSON.toJSONString(insertResCList));
        //TODO 这里注释
        List<SysResource> list = miDao.list(SysResource.class);
        List<SysResource> gen = list.stream().filter(it -> it.getPid().equals("0")).collect(Collectors.toList());
        List<SysResource> notGen = list.stream().filter(it -> !it.getPid().equals("0")).collect(Collectors.toList());
        log.info("list     {}", JSON.toJSONString(list));
        log.info("gen     {}", JSON.toJSONString(gen));
        log.info("notGen  {}", JSON.toJSONString(notGen));

        ArrayList<JSONObject> arrayList = TreeKit.listToTree(gen, notGen);
        log.info("全部资源树化结果      {}", JSON.toJSONString(arrayList));
        resources();
        return SRS.bySuccess(CacheKit.get("all_resource_list"));
    }


    @Override
    public SRS refreshRoleMenuAndResource(SRS param) {
        //缓存全部角色
        List<SysRole> sysRoles = roles();
        //查询角色菜单关联表
        List<String> roleIds = sysRoles.stream().map(SysRole::getId).collect(Collectors.toList());

        //缓存角色资源，角色菜单
        for (String roleId : roleIds) {
            //当前角色的全部资源
            List<Object> roleResourceIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select("resource_id").eq("role_id", roleId));
            //当前角色的全部菜单
            List<Object> roleMenuIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select("menu_id").eq("role_id", roleId));

            updateRoleResource(SRS.create().set("roleId", roleId).set("resourceIds", roleResourceIds));
            updateRoleMenu(SRS.create().set("roleId", roleId).set("menuIds", roleMenuIds));
        }
        return SRS.bySuccess();
    }

    //修改角色资源
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS updateRoleResource(SRS param) {
        String roleId = param.getString("roleId");
        JSONArray resourceIds = param.getJSONArray("resourceIds");

        //修改角色资源关联表
        //删除
        miDao.delete(new MiWrapper<>(SysLinkRoleResource.class).eq(SysLinkRoleResource.ROLE_ID, roleId));

        //重新插入
        ArrayList<SysLinkRoleResource> objects = new ArrayList<>();
        for (Object resourceId : resourceIds) {
            SysLinkRoleResource sysLinkRoleResource = new SysLinkRoleResource();
            sysLinkRoleResource.setRoleId(roleId);
            sysLinkRoleResource.setResourceId(resourceId.toString());
            objects.add(sysLinkRoleResource);
        }
        miDao.insertBatch(objects);

        //刷新缓存
        CacheKit.delete("cache-system-role-resource-url-" + roleId);
        CacheKit.delete("cache-system-role-resource-list-" + roleId);

        return SRS.bySuccess();
    }

    //修改角色菜单
    @Override
    public SRS updateRoleMenu(SRS param) {
        String roleId = param.getString("roleId");
        JSONArray menuIds = param.getJSONArray("menuIds");

        //修改角色菜单关联表
        //删除
        miDao.delete(new MiWrapper<>(SysLinkRoleMenu.class).eq(SysLinkRoleMenu.ROLE_ID, roleId));
        //重新插入
        ArrayList<SysLinkRoleMenu> objects = new ArrayList<>();
        for (Object menuId : menuIds) {
            SysLinkRoleMenu linkRoleMenu = new SysLinkRoleMenu();
            linkRoleMenu.setRoleId(roleId);
            linkRoleMenu.setMenuId(menuId.toString());
            objects.add(linkRoleMenu);
        }
        miDao.insertBatch(objects);

        //删除缓存
        CacheKit.delete("cache-system-role-menu-url-" + roleId);
        CacheKit.delete("cache-system-role-menu-list-" + roleId);
        return SRS.bySuccess();
    }

    //更新已存在资源的功能和名称
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SRS resourceRefreshAll(SRS param) {
        //更新已存在资源的功能和名称

        //项目中存在的资源
        ArrayList<ResEntity> listRes = ResourceHandler.getResMList();
        //数据库中的全部资源
        List<SysResource> listDbRes = miDao.list(SysResource.class);
        for (SysResource sysResource : listDbRes) {
            for (ResEntity resEntity : listRes) {
                if (sysResource.getUrl().equals(resEntity.getUrl())) {
                    sysResource.setName(resEntity.getName());
                    //sysResource.setAbility(resEntity.getAbility());
                }
            }
        }
        long l = miDao.updateBatchById(listDbRes);
        log.info("已刷新资源 共{}条", l);
        return SRS.bySuccess();
    }

    //刷新某个用户的角色
    @Override
    public SRS refreshUserRole(String userId) {
        return SRS.bySuccess();
    }

    //获取角色资源
    @Override
    public List<SysLinkRoleResource> getRoleResource(String roleId) {
        return (List<SysLinkRoleResource>) CacheKit.get("RoleResource-" + roleId);
    }

    //获取角色菜单
    @Override
    public List<SysLinkRoleMenu> getRoleMenu(String roleId) {
        return (List<SysLinkRoleMenu>) CacheKit.get("RoleMenu-" + roleId);
    }

    //获取用户角色
    @Override
    public List<SysLinkRoleUser> getUserRole(String userId) {
        return (List<SysLinkRoleUser>) CacheKit.get("UserRole-" + userId);
    }

    @Override
    public SRS insertDict(SysDict dict) {
        dict.insert();
        CacheKit.delete("cache-system-dict-list");
        return SRS.bySuccess();
    }

    @Override
    public SRS deleteDict(Object[] ids) {
        miDao.deleteByIds(SysDict.class, Arrays.asList(ids));
        CacheKit.delete("cache-system-dict-list");
        return SRS.bySuccess();
    }

    @Override
    public SRS updateDict(SysDict dict) {
        dict.updateById();
        CacheKit.delete("cache-system-dict-list");
        return SRS.bySuccess();
    }

    @Override
    public SRS pageDict(SRS param) {
        MiWrapper<SysDict> wrapper = new MiWrapper<>(SysDict.class);
        wrapper.like(notBlank(param.get("id")), SysDict.ID, param.get("id"));
        wrapper.like(notBlank(param.get("code")), SysDict.CODE, param.get("code"));
        wrapper.like(notBlank(param.get("value")), SysDict.VALUE, param.get("value"));
        wrapper.like(notBlank(param.get("name")), SysDict.NAME, param.get("name"));
        MiPage<SysDict> page = miDao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    @Override
    public SRS listDict(SRS param) {
        MiWrapper<SysDict> wrapper = new MiWrapper<>(SysDict.class);
        wrapper.like(notBlank(param.get("id")), SysDict.ID, param.get("id"));
        List<SysDict> list = miDao.list(wrapper);
        return SRS.bySuccess(list);
    }

    @Override
    public SRS infoDict(SRS param) {
        SysDict dict = miDao.selectById(SysDict.class, param.getString("id"));
        return SRS.bySuccess(dict);
    }

    public SRS insertMenu(SysMenu menu) {
        menu.insert();
        //删除菜单缓存
        CacheKit.delete("cache-system-menu-list");
        return SRS.bySuccess();
    }

    public SRS deleteMenu(Object[] ids) {
        miDao.deleteByIds(SysMenu.class, Arrays.asList(ids));

        //删除菜单缓存
        CacheKit.delete("cache-system-menu-list");
        //删除角色菜单缓存
        List<Object> roleIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.ROLE_ID).in(SysLinkRoleMenu.MENU_ID, Arrays.asList(ids)));
        for (Object roleId : roleIds) {
            CacheKit.delete("cache-system-role-menu-url-" + roleId);
            CacheKit.delete("cache-system-role-menu-list-" + roleId);
        }
        return SRS.bySuccess();
    }

    public SRS updateMenu(SysMenu menu) {
        menu.updateById();

        //删除菜单缓存
        CacheKit.delete("cache-system-menu-list");
        //删除角色菜单缓存
        String menuId = menu.getId();
        List<Object> roleIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleMenu.class).select(SysLinkRoleMenu.ROLE_ID).eq(SysLinkRoleMenu.MENU_ID, menuId));
        for (Object roleId : roleIds) {
            CacheKit.delete("cache-system-role-menu-url-" + roleId);
            CacheKit.delete("cache-system-role-menu-list-" + roleId);
        }
        return SRS.bySuccess();
    }

    public SRS pageMenu(SRS param) {
        MiWrapper<SysMenu> wrapper = new MiWrapper<>(SysMenu.class);
        wrapper.like(notBlank(param.get("id")), SysMenu.ID, param.get("id"));
        MiPage<SysMenu> page = miDao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    public SRS listMenu(SRS param) {
        MiWrapper<SysMenu> wrapper = new MiWrapper<>(SysMenu.class);
        wrapper.like(notBlank(param.get("id")), SysMenu.ID, param.get("id"));
        List<SysMenu> list = miDao.list(wrapper);
        return SRS.bySuccess(list);
    }

    public SRS infoMenu(SRS param) {
        SysMenu dict = miDao.selectById(SysMenu.class, param.getString("id"));
        return SRS.bySuccess(dict);
    }

    public SRS updateResource(SysResource resource) {
        resource.updateById();

        // 删除资源缓存
        CacheKit.delete("cache-system-resource-list");
        // 删除角色资源缓存
        String resourceId = resource.getId();
        List<Object> roleIds = miDao.listObjs(new MiWrapper<>(SysLinkRoleResource.class).select(SysLinkRoleResource.ROLE_ID).eq(SysLinkRoleResource.RESOURCE_ID, resourceId));
        for (Object roleId : roleIds) {
            CacheKit.delete("cache-system-role-resource-url-" + roleId);
            CacheKit.delete("cache-system-role-resource-list-" + roleId);
        }
        return SRS.bySuccess();
    }

    public SRS pageResource(SRS param) {
        MiWrapper<SysResource> wrapper = new MiWrapper<>(SysResource.class);
        wrapper.like(notBlank(param.get("id")), SysResource.ID, param.get("id"));
        MiPage<SysResource> page = miDao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    public SRS listResource(SRS param) {
        MiWrapper<SysResource> wrapper = new MiWrapper<>(SysResource.class);
        wrapper.like(notBlank(param.get("id")), SysResource.ID, param.get("id"));
        List<SysResource> list = miDao.list(wrapper);
        return SRS.bySuccess(list);
    }

    public SRS infoResource(SRS param) {
        SysResource dict = miDao.selectById(SysResource.class, param.getString("id"));
        return SRS.bySuccess(dict);
    }

    public SRS insertSysRole(SysRole role) {
        role.insert();
        //删除角色缓存
        CacheKit.delete("cache-system-role-list");
        return SRS.bySuccess();

    }

    public SRS deleteSysRole(Object[] ids) {
        miDao.deleteByIds(SysRole.class, Arrays.asList(ids));
        //删除角色缓存
        CacheKit.delete("cache-system-role-list");

        for (Object roleId : ids) {
            //删除角色菜单
            CacheKit.delete("cache-system-role-menu-url-" + roleId);
            CacheKit.delete("cache-system-role-menu-list-" + roleId);
            //删除角色资源
            CacheKit.delete("cache-system-role-resource-url-" + roleId);
            CacheKit.delete("cache-system-role-resource-list-" + roleId);
        }
        return SRS.bySuccess();

    }

    public SRS updateSysRole(SysRole role) {
        role.updateById();
        //删除角色缓存
        CacheKit.delete("cache-system-role-list");
        //删除角色菜单
        CacheKit.delete("cache-system-role-menu-url-" + role.getId());
        CacheKit.delete("cache-system-role-menu-list-" + role.getId());
        //删除角色资源
        CacheKit.delete("cache-system-role-resource-url-" + role.getId());
        CacheKit.delete("cache-system-role-resource-list-" + role.getId());
        return SRS.bySuccess();
    }


    public SRS pageSysRole(SRS param) {
        MiWrapper<SysRole> wrapper = new MiWrapper<>(SysRole.class);
        wrapper.like(notBlank(param.get("id")), SysRole.ID, param.get("id"));
        MiPage<SysRole> page = miDao.page(new MiPage<>(param), wrapper);
        return SRS.bySuccess(page);
    }

    public SRS listSysRole(SRS param) {
        MiWrapper<SysRole> wrapper = new MiWrapper<>(SysRole.class);
        wrapper.like(notBlank(param.get("id")), SysRole.ID, param.get("id"));
        List<SysRole> list = miDao.list(wrapper);
        return SRS.bySuccess(list);
    }

    public SRS infoSysRole(SRS param) {
        SysRole dict = miDao.selectById(SysRole.class, param.getString("id"));
        return SRS.bySuccess(dict);
    }

    public SRS login(SRS param) {
        return null;
    }

    public SRS updatePassword(SRS param) {
        return null;
    }

    public SRS insertSysUser(SysUser user) {
        return null;
    }

    public SRS deleteSysUser(Object[] ids) {
        return null;
    }

    public SRS updateSysUser(SysUser user) {
        return null;
    }

    public SRS listSysUser(SysUser user) {
        return null;
    }

    public SRS pageSysUser(SRS param) {
        return null;
    }

    public SRS infoSysUser(SRS param) {
        return null;
    }

    public SRS refreshToken(SRS param) {
        return null;
    }

    public SRS resetPassword(SRS param) {
        return null;
    }

}